package wang.raye.springcloud.zuul;


import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.util.RequestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UrlPathHelper;
import wang.raye.springcloud.zuul.service.ChannelService;

import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * 根据参数跳转的过滤器
 * Create by Raye on 2018年6月13日
 */
public class MyPreDecorationFilter extends ZuulFilter {
    private static final Log log = LogFactory.getLog(MyPreDecorationFilter.class);
    /** @deprecated */
    @Deprecated
    public static final int FILTER_ORDER = 5;
    private String dispatcherServletPath;
    private ZuulProperties properties;
    private UrlPathHelper urlPathHelper = new UrlPathHelper();
    private ChannelService service;

    public MyPreDecorationFilter(String dispatcherServletPath, ZuulProperties properties,ChannelService service) {
        this.properties = properties;
        this.urlPathHelper.setRemoveSemicolonContent(properties.isRemoveSemicolonContent());
        this.dispatcherServletPath = dispatcherServletPath;
        this.service = service;
    }

    public int filterOrder() {
        return 0;
    }

    public String filterType() {
        return "pre";
    }

    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return !ctx.containsKey("forward.to") && !ctx.containsKey("serviceId");
    }

    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());
        String location;
        String xforwardedfor;
        String remoteAddr;
        HttpServletRequest request = ctx.getRequest();
//        requestURI = requestURI.replaceAll("/scan","");
        String tenantid = request.getParameter("tenantid");
        String channelid = request.getParameter("channelid");
        if(StringUtils.isEmpty(tenantid)){
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);

            ctx.setResponseBody("{\"status\":\"fail\",\"message\":\"缺少参数tenantid\"}");
            ctx.getResponse().setContentType("text/html;charset=UTF-8");
            return null;
        }
        if(StringUtils.isEmpty(channelid)){
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);

            ctx.setResponseBody("{\"status\":\"fail\",\"message\":\"缺少参数channelid\"}");
            ctx.getResponse().setContentType("text/html;charset=UTF-8");
            return null;
        }
        location = service.selectCallurl(tenantid,channelid);

        if(!StringUtils.isEmpty(location)){
            ctx.put("requestURI", requestURI);
            ctx.put("proxy", "api-a");
            if (!location.startsWith("http:") && !location.startsWith("https:")) {
                if (location.startsWith("forward:")) {
                    ctx.set("forward.to", StringUtils.cleanPath(location.substring("forward:".length()) + requestURI));
                    ctx.setRouteHost((URL)null);
                    return null;
                }

                ctx.set("serviceId", "api-a");
                ctx.setRouteHost((URL)null);
                ctx.addOriginResponseHeader("X-Zuul-ServiceId", location);
            } else {
                ctx.setRouteHost(this.getUrl(location));
                ctx.addOriginResponseHeader("X-Zuul-Service", location);
            }
        }else {
            log.warn("No route found for uri: " + requestURI);
            xforwardedfor = this.dispatcherServletPath;
            if (RequestUtils.isZuulServletRequest()) {
                log.debug("zuulServletPath=" + this.properties.getServletPath());
                location = requestURI.replaceFirst(this.properties.getServletPath(), "");
                log.debug("Replaced Zuul servlet path:" + location);
            } else {
                log.debug("dispatcherServletPath=" + this.dispatcherServletPath);
                location = requestURI.replaceFirst(this.dispatcherServletPath, "");
                log.debug("Replaced DispatcherServlet servlet path:" + location);
            }

            if (!location.startsWith("/")) {
                location = "/" + location;
            }

            remoteAddr = xforwardedfor + location;
            remoteAddr = remoteAddr.replaceAll("//", "/");
            ctx.set("forward.to", remoteAddr);
        }

        return null;
    }

    private void addProxyHeaders(RequestContext ctx, Route route) {
        HttpServletRequest request = ctx.getRequest();
        String host = this.toHostHeader(request);
        String port = String.valueOf(request.getServerPort());
        String proto = request.getScheme();
        if (this.hasHeader(request, "X-Forwarded-Host")) {
            host = request.getHeader("X-Forwarded-Host") + "," + host;
            if (!this.hasHeader(request, "X-Forwarded-Port")) {
                if (this.hasHeader(request, "X-Forwarded-Proto")) {
                    StringBuilder builder = new StringBuilder();
                    String[] var8 = StringUtils.commaDelimitedListToStringArray(request.getHeader("X-Forwarded-Proto"));
                    int var9 = var8.length;

                    for(int var10 = 0; var10 < var9; ++var10) {
                        String previous = var8[var10];
                        if (builder.length() > 0) {
                            builder.append(",");
                        }

                        builder.append("https".equals(previous) ? 443 : 80);
                    }

                    builder.append(",").append(port);
                    port = builder.toString();
                }
            } else {
                port = request.getHeader("X-Forwarded-Port") + "," + port;
            }
        }

        if (this.hasHeader(request, "X-Forwarded-Proto")) {
            proto = request.getHeader("X-Forwarded-Proto") + "," + proto;
        }

        ctx.addZuulRequestHeader("X-Forwarded-Host", host);
        ctx.addZuulRequestHeader("X-Forwarded-Port", port);
        ctx.addZuulRequestHeader("X-Forwarded-Proto", proto);
        this.addProxyPrefix(ctx, route);
    }

    private boolean hasHeader(HttpServletRequest request, String name) {
        return StringUtils.hasLength(request.getHeader(name));
    }

    private void addProxyPrefix(RequestContext ctx, Route route) {
        String forwardedPrefix = ctx.getRequest().getHeader("X-Forwarded-Prefix");
        String contextPath = ctx.getRequest().getContextPath();
        String prefix = StringUtils.hasLength(forwardedPrefix) ? forwardedPrefix : (StringUtils.hasLength(contextPath) ? contextPath : null);
        if (StringUtils.hasText(route.getPrefix())) {
            StringBuilder newPrefixBuilder = new StringBuilder();
            if (prefix != null) {
                if (prefix.endsWith("/") && route.getPrefix().startsWith("/")) {
                    newPrefixBuilder.append(prefix, 0, prefix.length() - 1);
                } else {
                    newPrefixBuilder.append(prefix);
                }
            }

            newPrefixBuilder.append(route.getPrefix());
            prefix = newPrefixBuilder.toString();
        }

        if (prefix != null) {
            ctx.addZuulRequestHeader("X-Forwarded-Prefix", prefix);
        }

    }

    private String toHostHeader(HttpServletRequest request) {
        int port = request.getServerPort();
        return (port != 80 || !"http".equals(request.getScheme())) && (port != 443 || !"https".equals(request.getScheme())) ? request.getServerName() + ":" + port : request.getServerName();
    }

    private URL getUrl(String target) {
        try {
            return new URL(target);
        } catch (MalformedURLException var3) {
            throw new IllegalStateException("Target URL is malformed", var3);
        }
    }
}
